package com.hubspot.singularity.executor.config;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.hubspot.singularity.SingularityShellCommand;
import com.hubspot.singularity.executor.SingularityExecutorLogrotateFrequency;
import com.hubspot.singularity.executor.models.ThreadCheckerType;
import com.hubspot.singularity.executor.shells.SingularityExecutorShellCommandDescriptor;
import com.hubspot.singularity.executor.utils.MesosUtils;
import com.hubspot.singularity.runner.base.configuration.BaseRunnerConfiguration;
import com.hubspot.singularity.runner.base.configuration.Configuration;
import com.hubspot.singularity.runner.base.constraints.DirectoryExists;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;

@Configuration(
  filename = "/etc/singularity.executor.yaml",
  consolidatedField = "executor"
)
public class SingularityExecutorConfiguration extends BaseRunnerConfiguration {
  @NotEmpty
  @JsonProperty
  private String executorJavaLog = "executor.java.log";

  @NotEmpty
  @JsonProperty
  private String executorBashLog = "executor.bash.log";

  @NotEmpty
  @JsonProperty
  private String defaultRunAsUser;

  @NotEmpty
  @JsonProperty
  private String taskAppDirectory = "app";

  @Min(0)
  @JsonProperty
  private long shutdownTimeoutWaitMillis = TimeUnit.MINUTES.toMillis(5);

  @Min(0)
  @JsonProperty
  private long initialIdleExecutorShutdownWaitMillis = TimeUnit.MINUTES.toMillis(1);

  @Min(0)
  @JsonProperty
  private long idleExecutorShutdownWaitMillis = TimeUnit.SECONDS.toMillis(10);

  @Min(0)
  @JsonProperty
  private long stopDriverAfterMillis = TimeUnit.SECONDS.toMillis(1);

  @NotEmpty
  @DirectoryExists
  @JsonProperty
  private String globalTaskDefinitionDirectory;

  @NotEmpty
  @JsonProperty
  private String globalTaskDefinitionSuffix = ".task.json";

  @Min(1)
  @JsonProperty
  private long hardKillAfterMillis = TimeUnit.MINUTES.toMillis(3);

  @Min(1)
  @JsonProperty
  private int killThreads = 1;

  @Min(1)
  @JsonProperty
  private int threadCheckThreads = 1;

  @Min(1)
  @JsonProperty
  private long checkThreadsEveryMillis = TimeUnit.SECONDS.toMillis(5);

  @Min(0)
  @JsonProperty
  private int maxTaskMessageLength = 80;

  @NotEmpty
  @JsonProperty
  private String logrotateCommand = "logrotate";

  @NotEmpty
  @JsonProperty
  private String logrotateStateFile = "logrotate.status";

  @NotEmpty
  @DirectoryExists
  @JsonProperty
  private String logrotateConfDirectory = "/etc/logrotate.d";

  @NotEmpty
  @JsonProperty
  private String logrotateHourlyConfDirectory = "/etc/logrotate.d/hourly";

  @NotEmpty
  @JsonProperty
  private String logrotateToDirectory = "logs";

  @Min(1)
  @JsonProperty
  private int logrotateMaxageDays = 7;

  @Min(1)
  @JsonProperty
  private int logrotateCount = 20;

  @NotEmpty
  @JsonProperty
  private String logrotateDateformat = "%Y%m%d%s";

  @NotEmpty
  @JsonProperty
  private String logrotateExtrasDateformat = "%Y%m%d";

  @JsonProperty
  private boolean ignoreLogrotateOutput = false;

  @NotNull
  @JsonProperty
  private LogrotateCompressionSettings logrotateCompressionSettings = LogrotateCompressionSettings.empty();

  @NotNull
  @JsonProperty
  private List<SingularityExecutorLogrotateAdditionalFile> logrotateAdditionalFiles = Collections.emptyList();

  @Min(1)
  @JsonProperty
  private int tailLogLinesToSave = 2500;

  @JsonProperty
  private boolean useLocalDownloadService = false;

  @Min(1)
  @JsonProperty
  private long localDownloadServiceTimeoutMillis = TimeUnit.MINUTES.toMillis(3);

  @Min(1)
  @JsonProperty
  private int localDownloadServiceMaxConnections = 25;

  @JsonProperty
  private Optional<Integer> maxTaskThreads = Optional.empty();

  @JsonProperty
  private String dockerPrefix = "se-";

  @Min(5)
  @JsonProperty
  private int dockerStopTimeout = 15;

  @JsonProperty
  @NotNull
  private List<String> dockerInheritVariables = new ArrayList<>();

  @NotEmpty
  @JsonProperty
  private String cgroupsMesosCpuTasksFormat = "/cgroup/cpu/%s/tasks";

  @NotEmpty
  @JsonProperty
  private String procCgroupFormat = "/proc/%s/cgroup";

  @NotEmpty
  @JsonProperty
  private String switchUserCommandFormat = "sudo -E -u %s";

  @JsonProperty
  @NotEmpty
  private List<String> artifactSignatureVerificationCommand = Arrays.asList(
    "/usr/bin/gpg",
    "--verify",
    "{artifactSignaturePath}"
  );

  @JsonProperty
  private boolean failTaskOnInvalidArtifactSignature = true;

  @JsonProperty
  private boolean failOnArtifactWithNoMatchingSignature = false;

  private boolean failOnSignatureWithNoMatchingArtifact = false;

  @JsonProperty
  @NotEmpty
  private String signatureVerifyOut = "executor.gpg.out";

  @JsonProperty
  public List<SingularityExecutorShellCommandDescriptor> shellCommands = Collections.emptyList();

  @NotEmpty
  @JsonProperty
  public String shellCommandOutFile = "executor.commands.{NAME}.{TIMESTAMP}.log";

  @NotEmpty
  @JsonProperty
  private String shellCommandPidPlaceholder = "{PID}";

  @NotEmpty
  @JsonProperty
  private String shellCommandUserPlaceholder = "{USER}";

  @NotEmpty
  @JsonProperty
  private String shellCommandPidFile = ".task-pid";

  @JsonProperty
  private List<String> shellCommandPrefix = Collections.emptyList();

  @JsonProperty
  private Optional<SingularityShellCommand> runShellCommandBeforeKillDueToThreads = Optional.empty();

  @JsonProperty
  private int dockerClientTimeLimitSeconds = 300;

  @JsonProperty
  private int dockerClientConnectionPoolSize = 5;

  @JsonProperty
  private int maxDockerPullAttempts = 2;

  @JsonProperty
  private Optional<SingularityExecutorDockerAuthConfig> dockerAuthConfig = Optional.empty();

  @JsonProperty
  private ThreadCheckerType threadCheckerType = ThreadCheckerType.PS;

  @JsonProperty
  private SingularityExecutorLogrotateFrequency logrotateFrequency =
    SingularityExecutorLogrotateFrequency.DAILY;

  @NotEmpty
  @JsonProperty
  private String cronDirectory = "/etc/cron.d";

  @JsonProperty
  private boolean useFileAttributes = false;

  @JsonProperty
  private int defaultHealthcheckMaxRetries = 6;

  private int defaultHealthcheckBaseTimeoutSeconds = 30;

  private int defaultHealthcheckInternvalSeconds = 5;

  private int defaultCfsPeriod = 100000;

  private String extraScriptContent = "";

  private String extraDockerScriptContent = "";

  private Optional<Long> maxServiceLogSizeMb = Optional.empty();

  @JsonProperty
  private boolean verifyAssignedPorts = false;

  public SingularityExecutorConfiguration() {
    super(Optional.of("singularity-executor.log"));
  }

  public String getShellCommandPidPlaceholder() {
    return shellCommandPidPlaceholder;
  }

  public void setShellCommandPidPlaceholder(String shellCommandPidPlaceholder) {
    this.shellCommandPidPlaceholder = shellCommandPidPlaceholder;
  }

  public String getShellCommandUserPlaceholder() {
    return shellCommandUserPlaceholder;
  }

  public void setShellCommandUserPlaceholder(String shellCommandUserPlaceholder) {
    this.shellCommandUserPlaceholder = shellCommandUserPlaceholder;
  }

  public List<SingularityExecutorLogrotateAdditionalFile> getLogrotateAdditionalFiles() {
    return logrotateAdditionalFiles;
  }

  public void setLogrotateAdditionalFiles(
    List<SingularityExecutorLogrotateAdditionalFile> logrotateAdditionalFiles
  ) {
    this.logrotateAdditionalFiles = logrotateAdditionalFiles;
  }

  public String getExecutorJavaLog() {
    return executorJavaLog;
  }

  public String getExecutorBashLog() {
    return executorBashLog;
  }

  public String getDefaultRunAsUser() {
    return defaultRunAsUser;
  }

  public String getTaskAppDirectory() {
    return taskAppDirectory;
  }

  public long getShutdownTimeoutWaitMillis() {
    return shutdownTimeoutWaitMillis;
  }

  public long getIdleExecutorShutdownWaitMillis() {
    return idleExecutorShutdownWaitMillis;
  }

  public int getLocalDownloadServiceMaxConnections() {
    return localDownloadServiceMaxConnections;
  }

  public void setLocalDownloadServiceMaxConnections(
    int localDownloadServiceMaxConnections
  ) {
    this.localDownloadServiceMaxConnections = localDownloadServiceMaxConnections;
  }

  public long getStopDriverAfterMillis() {
    return stopDriverAfterMillis;
  }

  public String getGlobalTaskDefinitionDirectory() {
    return globalTaskDefinitionDirectory;
  }

  public String getGlobalTaskDefinitionSuffix() {
    return globalTaskDefinitionSuffix;
  }

  public long getHardKillAfterMillis() {
    return hardKillAfterMillis;
  }

  public int getKillThreads() {
    return killThreads;
  }

  public int getThreadCheckThreads() {
    return threadCheckThreads;
  }

  public long getCheckThreadsEveryMillis() {
    return checkThreadsEveryMillis;
  }

  public int getMaxTaskMessageLength() {
    return maxTaskMessageLength;
  }

  public String getLogrotateCommand() {
    return logrotateCommand;
  }

  public String getLogrotateStateFile() {
    return logrotateStateFile;
  }

  public String getLogrotateConfDirectory() {
    return logrotateConfDirectory;
  }

  public String getLogrotateHourlyConfDirectory() {
    return logrotateHourlyConfDirectory;
  }

  public String getLogrotateToDirectory() {
    return logrotateToDirectory;
  }

  public int getLogrotateMaxageDays() {
    return logrotateMaxageDays;
  }

  public int getLogrotateCount() {
    return logrotateCount;
  }

  public String getLogrotateDateformat() {
    return logrotateDateformat;
  }

  public String getLogrotateExtrasDateformat() {
    return logrotateExtrasDateformat;
  }

  public boolean isIgnoreLogrotateOutput() {
    return ignoreLogrotateOutput;
  }

  public void setIgnoreLogrotateOutput(boolean ignoreLogrotateOutput) {
    this.ignoreLogrotateOutput = ignoreLogrotateOutput;
  }

  public int getTailLogLinesToSave() {
    return tailLogLinesToSave;
  }

  public boolean isUseLocalDownloadService() {
    return useLocalDownloadService;
  }

  public long getLocalDownloadServiceTimeoutMillis() {
    return localDownloadServiceTimeoutMillis;
  }

  public Optional<Integer> getMaxTaskThreads() {
    return maxTaskThreads;
  }

  public String getDockerPrefix() {
    return dockerPrefix;
  }

  public int getDockerStopTimeout() {
    return dockerStopTimeout;
  }

  public List<String> getDockerInheritVariables() {
    return dockerInheritVariables;
  }

  public void setDockerInheritVariables(List<String> dockerInheritVariables) {
    this.dockerInheritVariables = dockerInheritVariables;
  }

  @JsonIgnore
  public Path getTaskDefinitionPath(String taskId) {
    return Paths
      .get(getGlobalTaskDefinitionDirectory())
      .resolve(
        MesosUtils.getSafeTaskIdForDirectory(taskId) + getGlobalTaskDefinitionSuffix()
      );
  }

  public void setExecutorJavaLog(String executorJavaLog) {
    this.executorJavaLog = executorJavaLog;
  }

  public void setExecutorBashLog(String executorBashLog) {
    this.executorBashLog = executorBashLog;
  }

  public void setDefaultRunAsUser(String defaultRunAsUser) {
    this.defaultRunAsUser = defaultRunAsUser;
  }

  public void setTaskAppDirectory(String taskAppDirectory) {
    this.taskAppDirectory = taskAppDirectory;
  }

  public void setShutdownTimeoutWaitMillis(long shutdownTimeoutWaitMillis) {
    this.shutdownTimeoutWaitMillis = shutdownTimeoutWaitMillis;
  }

  public void setIdleExecutorShutdownWaitMillis(long idleExecutorShutdownWaitMillis) {
    this.idleExecutorShutdownWaitMillis = idleExecutorShutdownWaitMillis;
  }

  public void setStopDriverAfterMillis(long stopDriverAfterMillis) {
    this.stopDriverAfterMillis = stopDriverAfterMillis;
  }

  public void setGlobalTaskDefinitionDirectory(String globalTaskDefinitionDirectory) {
    this.globalTaskDefinitionDirectory = globalTaskDefinitionDirectory;
  }

  public void setGlobalTaskDefinitionSuffix(String globalTaskDefinitionSuffix) {
    this.globalTaskDefinitionSuffix = globalTaskDefinitionSuffix;
  }

  public void setHardKillAfterMillis(long hardKillAfterMillis) {
    this.hardKillAfterMillis = hardKillAfterMillis;
  }

  public void setKillThreads(int killThreads) {
    this.killThreads = killThreads;
  }

  public void setThreadCheckThreads(int threadCheckThreads) {
    this.threadCheckThreads = threadCheckThreads;
  }

  public void setCheckThreadsEveryMillis(long checkThreadsEveryMillis) {
    this.checkThreadsEveryMillis = checkThreadsEveryMillis;
  }

  public void setMaxTaskMessageLength(int maxTaskMessageLength) {
    this.maxTaskMessageLength = maxTaskMessageLength;
  }

  public void setLogrotateCommand(String logrotateCommand) {
    this.logrotateCommand = logrotateCommand;
  }

  public void setLogrotateStateFile(String logrotateStateFile) {
    this.logrotateStateFile = logrotateStateFile;
  }

  public void setLogrotateConfDirectory(String logrotateConfDirectory) {
    this.logrotateConfDirectory = logrotateConfDirectory;
  }

  public void setLogrotateToDirectory(String logrotateToDirectory) {
    this.logrotateToDirectory = logrotateToDirectory;
  }

  public void setLogrotateMaxageDays(int logrotateMaxageDays) {
    this.logrotateMaxageDays = logrotateMaxageDays;
  }

  public void setLogrotateCount(int logrotateCount) {
    this.logrotateCount = logrotateCount;
  }

  public void setLogrotateDateformat(String logrotateDateformat) {
    this.logrotateDateformat = logrotateDateformat;
  }

  public void setLogrotateExtrasDateformat(String logrotateExtrasDateformat) {
    this.logrotateExtrasDateformat = logrotateExtrasDateformat;
  }

  public void setTailLogLinesToSave(int tailLogLinesToSave) {
    this.tailLogLinesToSave = tailLogLinesToSave;
  }

  public void setUseLocalDownloadService(boolean useLocalDownloadService) {
    this.useLocalDownloadService = useLocalDownloadService;
  }

  public void setLocalDownloadServiceTimeoutMillis(
    long localDownloadServiceTimeoutMillis
  ) {
    this.localDownloadServiceTimeoutMillis = localDownloadServiceTimeoutMillis;
  }

  public void setMaxTaskThreads(Optional<Integer> maxTaskThreads) {
    this.maxTaskThreads = maxTaskThreads;
  }

  public void setDockerPrefix(String dockerPrefix) {
    this.dockerPrefix = dockerPrefix;
  }

  public void setDockerStopTimeout(int dockerStopTimeout) {
    this.dockerStopTimeout = dockerStopTimeout;
  }

  public String getCgroupsMesosCpuTasksFormat() {
    return cgroupsMesosCpuTasksFormat;
  }

  public void setCgroupsMesosCpuTasksFormat(String cgroupsMesosCpuTasksFormat) {
    this.cgroupsMesosCpuTasksFormat = cgroupsMesosCpuTasksFormat;
  }

  public String getProcCgroupFormat() {
    return procCgroupFormat;
  }

  public void setProcCgroupFormat(String procCgroupFormat) {
    this.procCgroupFormat = procCgroupFormat;
  }

  public String getSwitchUserCommandFormat() {
    return switchUserCommandFormat;
  }

  public void setSwitchUserCommandFormat(String switchUserCommandFormat) {
    this.switchUserCommandFormat = switchUserCommandFormat;
  }

  public List<String> getArtifactSignatureVerificationCommand() {
    return artifactSignatureVerificationCommand;
  }

  public void setArtifactSignatureVerificationCommand(
    List<String> artifactSignatureVerificationCommand
  ) {
    this.artifactSignatureVerificationCommand = artifactSignatureVerificationCommand;
  }

  public boolean isFailTaskOnInvalidArtifactSignature() {
    return failTaskOnInvalidArtifactSignature;
  }

  public void setFailTaskOnInvalidArtifactSignature(
    boolean failTaskOnInvalidArtifactSignature
  ) {
    this.failTaskOnInvalidArtifactSignature = failTaskOnInvalidArtifactSignature;
  }

  public boolean isFailOnArtifactWithNoMatchingSignature() {
    return failOnArtifactWithNoMatchingSignature;
  }

  public void setFailOnArtifactWithNoMatchingSignature(
    boolean failOnArtifactWithNoMatchingSignature
  ) {
    this.failOnArtifactWithNoMatchingSignature = failOnArtifactWithNoMatchingSignature;
  }

  public String getSignatureVerifyOut() {
    return signatureVerifyOut;
  }

  public void setSignatureVerifyOut(String signatureVerifyOut) {
    this.signatureVerifyOut = signatureVerifyOut;
  }

  public List<SingularityExecutorShellCommandDescriptor> getShellCommands() {
    return shellCommands;
  }

  public void setShellCommands(
    List<SingularityExecutorShellCommandDescriptor> shellCommands
  ) {
    this.shellCommands = shellCommands;
  }

  public String getShellCommandOutFile() {
    return shellCommandOutFile;
  }

  public void setShellCommandOutFile(String shellCommandOutFile) {
    this.shellCommandOutFile = shellCommandOutFile;
  }

  public String getShellCommandPidFile() {
    return shellCommandPidFile;
  }

  public void setShellCommandPidFile(String shellCommandPidFile) {
    this.shellCommandPidFile = shellCommandPidFile;
  }

  public List<String> getShellCommandPrefix() {
    return shellCommandPrefix;
  }

  public void setShellCommandPrefix(List<String> shellCommandPrefix) {
    this.shellCommandPrefix = shellCommandPrefix;
  }

  public Optional<SingularityShellCommand> getRunShellCommandBeforeKillDueToThreads() {
    return runShellCommandBeforeKillDueToThreads;
  }

  public void setRunShellCommandBeforeKillDueToThreads(
    Optional<SingularityShellCommand> runShellCommandBeforeKillDueToThreads
  ) {
    this.runShellCommandBeforeKillDueToThreads = runShellCommandBeforeKillDueToThreads;
  }

  public int getDockerClientTimeLimitSeconds() {
    return dockerClientTimeLimitSeconds;
  }

  public void setDockerClientTimeLimitSeconds(int dockerClientTimeLimitMs) {
    this.dockerClientTimeLimitSeconds = dockerClientTimeLimitMs;
  }

  public int getDockerClientConnectionPoolSize() {
    return dockerClientConnectionPoolSize;
  }

  public void setDockerClientConnectionPoolSize(int dockerClientConnectionPoolSize) {
    this.dockerClientConnectionPoolSize = dockerClientConnectionPoolSize;
  }

  public int getMaxDockerPullAttempts() {
    return maxDockerPullAttempts;
  }

  public void setMaxDockerPullAttempts(int maxDockerPullAttempts) {
    this.maxDockerPullAttempts = maxDockerPullAttempts;
  }

  public Optional<SingularityExecutorDockerAuthConfig> getDockerAuthConfig() {
    return dockerAuthConfig;
  }

  public void setDockerAuthConfig(
    Optional<SingularityExecutorDockerAuthConfig> dockerAuthConfig
  ) {
    this.dockerAuthConfig = dockerAuthConfig;
  }

  public ThreadCheckerType getThreadCheckerType() {
    return threadCheckerType;
  }

  public void setThreadCheckerType(ThreadCheckerType threadCheckerType) {
    this.threadCheckerType = threadCheckerType;
  }

  public SingularityExecutorLogrotateFrequency getLogrotateFrequency() {
    return logrotateFrequency;
  }

  public void setLogrotateFrequency(
    SingularityExecutorLogrotateFrequency logrotateFrequency
  ) {
    this.logrotateFrequency = logrotateFrequency;
  }

  public String getCronDirectory() {
    return cronDirectory;
  }

  public void setCronDirectory(String cronDirectory) {
    this.cronDirectory = cronDirectory;
  }

  public boolean isUseFileAttributes() {
    return useFileAttributes;
  }

  public SingularityExecutorConfiguration setUseFileAttributes(
    boolean useFileAttributes
  ) {
    this.useFileAttributes = useFileAttributes;
    return this;
  }

  public LogrotateCompressionSettings getLogrotateCompressionSettings() {
    return logrotateCompressionSettings;
  }

  public void setLogrotateCompressionSettings(
    LogrotateCompressionSettings logrotateCompressionSettings
  ) {
    this.logrotateCompressionSettings = logrotateCompressionSettings;
  }

  public long getInitialIdleExecutorShutdownWaitMillis() {
    return initialIdleExecutorShutdownWaitMillis;
  }

  public void setInitialIdleExecutorShutdownWaitMillis(
    long initialIdleExecutorShutdownWaitMillis
  ) {
    this.initialIdleExecutorShutdownWaitMillis = initialIdleExecutorShutdownWaitMillis;
  }

  public int getDefaultCfsPeriod() {
    return defaultCfsPeriod;
  }

  public SingularityExecutorConfiguration setDefaultCfsPeriod(int defaultCfsPeriod) {
    this.defaultCfsPeriod = defaultCfsPeriod;
    return this;
  }

  public String getExtraScriptContent() {
    return extraScriptContent;
  }

  public void setExtraScriptContent(String extraScriptContent) {
    this.extraScriptContent = extraScriptContent;
  }

  public String getExtraDockerScriptContent() {
    return extraDockerScriptContent;
  }

  public void setExtraDockerScriptContent(String extraDockerScriptContent) {
    this.extraDockerScriptContent = extraDockerScriptContent;
  }

  public int getDefaultHealthcheckMaxRetries() {
    return defaultHealthcheckMaxRetries;
  }

  public void setDefaultHealthcheckMaxRetries(int defaultHealthcheckMaxRetries) {
    this.defaultHealthcheckMaxRetries = defaultHealthcheckMaxRetries;
  }

  public Optional<Long> getMaxServiceLogSizeMb() {
    return maxServiceLogSizeMb;
  }

  public void setMaxServiceLogSizeMb(Optional<Long> maxServiceLogSizeMb) {
    this.maxServiceLogSizeMb = maxServiceLogSizeMb;
  }

  public boolean isVerifyAssignedPorts() {
    return verifyAssignedPorts;
  }

  public void setVerifyAssignedPorts(boolean verifyAssignedPorts) {
    this.verifyAssignedPorts = verifyAssignedPorts;
  }

  public int getDefaultHealthcheckBaseTimeoutSeconds() {
    return defaultHealthcheckBaseTimeoutSeconds;
  }

  public void setDefaultHealthcheckBaseTimeoutSeconds(
    int defaultHealthcheckBaseTimeoutSeconds
  ) {
    this.defaultHealthcheckBaseTimeoutSeconds = defaultHealthcheckBaseTimeoutSeconds;
  }

  public int getDefaultHealthcheckInternvalSeconds() {
    return defaultHealthcheckInternvalSeconds;
  }

  public void setDefaultHealthcheckInternvalSeconds(
    int defaultHealthcheckInternvalSeconds
  ) {
    this.defaultHealthcheckInternvalSeconds = defaultHealthcheckInternvalSeconds;
  }

  public void setLogrotateHourlyConfDirectory(String logrotateHourlyConfDirectory) {
    this.logrotateHourlyConfDirectory = logrotateHourlyConfDirectory;
  }

  public boolean isFailOnSignatureWithNoMatchingArtifact() {
    return failOnSignatureWithNoMatchingArtifact;
  }

  public void setFailOnSignatureWithNoMatchingArtifact(
    boolean failOnSignatureWithNoMatchingArtifact
  ) {
    this.failOnSignatureWithNoMatchingArtifact = failOnSignatureWithNoMatchingArtifact;
  }

  @Override
  public String toString() {
    return (
      "SingularityExecutorConfiguration{" +
      "executorJavaLog='" +
      executorJavaLog +
      '\'' +
      ", executorBashLog='" +
      executorBashLog +
      '\'' +
      ", defaultRunAsUser='" +
      defaultRunAsUser +
      '\'' +
      ", taskAppDirectory='" +
      taskAppDirectory +
      '\'' +
      ", shutdownTimeoutWaitMillis=" +
      shutdownTimeoutWaitMillis +
      ", initialIdleExecutorShutdownWaitMillis=" +
      initialIdleExecutorShutdownWaitMillis +
      ", idleExecutorShutdownWaitMillis=" +
      idleExecutorShutdownWaitMillis +
      ", stopDriverAfterMillis=" +
      stopDriverAfterMillis +
      ", globalTaskDefinitionDirectory='" +
      globalTaskDefinitionDirectory +
      '\'' +
      ", globalTaskDefinitionSuffix='" +
      globalTaskDefinitionSuffix +
      '\'' +
      ", hardKillAfterMillis=" +
      hardKillAfterMillis +
      ", killThreads=" +
      killThreads +
      ", threadCheckThreads=" +
      threadCheckThreads +
      ", checkThreadsEveryMillis=" +
      checkThreadsEveryMillis +
      ", maxTaskMessageLength=" +
      maxTaskMessageLength +
      ", logrotateCommand='" +
      logrotateCommand +
      '\'' +
      ", logrotateStateFile='" +
      logrotateStateFile +
      '\'' +
      ", logrotateConfDirectory='" +
      logrotateConfDirectory +
      '\'' +
      ", logrotateHourlyConfDirectory='" +
      logrotateHourlyConfDirectory +
      '\'' +
      ", logrotateToDirectory='" +
      logrotateToDirectory +
      '\'' +
      ", logrotateMaxageDays=" +
      logrotateMaxageDays +
      ", logrotateCount=" +
      logrotateCount +
      ", logrotateDateformat='" +
      logrotateDateformat +
      '\'' +
      ", logrotateExtrasDateformat='" +
      logrotateExtrasDateformat +
      '\'' +
      ", ignoreLogrotateOutput=" +
      ignoreLogrotateOutput +
      ", logrotateCompressionSettings=" +
      logrotateCompressionSettings +
      ", logrotateAdditionalFiles=" +
      logrotateAdditionalFiles +
      ", tailLogLinesToSave=" +
      tailLogLinesToSave +
      ", useLocalDownloadService=" +
      useLocalDownloadService +
      ", localDownloadServiceTimeoutMillis=" +
      localDownloadServiceTimeoutMillis +
      ", localDownloadServiceMaxConnections=" +
      localDownloadServiceMaxConnections +
      ", maxTaskThreads=" +
      maxTaskThreads +
      ", dockerPrefix='" +
      dockerPrefix +
      '\'' +
      ", dockerStopTimeout=" +
      dockerStopTimeout +
      ", cgroupsMesosCpuTasksFormat='" +
      cgroupsMesosCpuTasksFormat +
      '\'' +
      ", procCgroupFormat='" +
      procCgroupFormat +
      '\'' +
      ", switchUserCommandFormat='" +
      switchUserCommandFormat +
      '\'' +
      ", artifactSignatureVerificationCommand=" +
      artifactSignatureVerificationCommand +
      ", failTaskOnInvalidArtifactSignature=" +
      failTaskOnInvalidArtifactSignature +
      ", failOnArtifactWithNoMatchingSignature=" +
      failOnArtifactWithNoMatchingSignature +
      ", signatureVerifyOut='" +
      signatureVerifyOut +
      '\'' +
      ", shellCommands=" +
      shellCommands +
      ", shellCommandOutFile='" +
      shellCommandOutFile +
      '\'' +
      ", shellCommandPidPlaceholder='" +
      shellCommandPidPlaceholder +
      '\'' +
      ", shellCommandUserPlaceholder='" +
      shellCommandUserPlaceholder +
      '\'' +
      ", shellCommandPidFile='" +
      shellCommandPidFile +
      '\'' +
      ", shellCommandPrefix=" +
      shellCommandPrefix +
      ", runShellCommandBeforeKillDueToThreads=" +
      runShellCommandBeforeKillDueToThreads +
      ", dockerClientTimeLimitSeconds=" +
      dockerClientTimeLimitSeconds +
      ", dockerClientConnectionPoolSize=" +
      dockerClientConnectionPoolSize +
      ", maxDockerPullAttempts=" +
      maxDockerPullAttempts +
      ", dockerAuthConfig=" +
      dockerAuthConfig +
      ", threadCheckerType=" +
      threadCheckerType +
      ", logrotateFrequency=" +
      logrotateFrequency +
      ", cronDirectory='" +
      cronDirectory +
      '\'' +
      ", useFileAttributes=" +
      useFileAttributes +
      ", defaultHealthcheckMaxRetries=" +
      defaultHealthcheckMaxRetries +
      ", defaultHealthcheckBaseTimeoutSeconds=" +
      defaultHealthcheckBaseTimeoutSeconds +
      ", defaultHealthcheckInternvalSeconds=" +
      defaultHealthcheckInternvalSeconds +
      ", defaultCfsPeriod=" +
      defaultCfsPeriod +
      ", extraScriptContent='" +
      extraScriptContent +
      '\'' +
      ", extraDockerScriptContent='" +
      extraDockerScriptContent +
      '\'' +
      ", maxServiceLogSizeMb=" +
      maxServiceLogSizeMb +
      ", verifyAssignedPorts=" +
      verifyAssignedPorts +
      "} " +
      super.toString()
    );
  }
}
